package com.howard.base.interceptor;

import java.util.Collection;
import java.util.List;
import java.util.Map;

import org.apache.struts2.dispatcher.ServletRedirectResult;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.Result;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;

/**
 * 表现层访问控制拦截器
 *
 * @author 程进之
 * @since JDK1.6
 * @history 2012-7-23 程进之 新建
 */
public class RedirectResultInterceptor extends AbstractInterceptor {

    /** KEY_ACTION_ERRORS */
    private final static String KEY_ACTION_ERRORS = "last.action.actionerrors";

    /** KEY_ACTION_MESSAGES */
    private final static String KEY_ACTION_MESSAGES = "last.action.actionmessages";

    /** KEY_FIELD_ERRORS */
    private final static String KEY_FIELD_ERRORS = "last.action.fielderrors";

    private String position;

    public String getPosition() {
        return position;
    }

    public void setPosition(String position) {
        this.position = position;
    }

    public boolean isTop() {
        return "top".equalsIgnoreCase(this.position);
    }

    public boolean isBottom() {
        return "bottom".equalsIgnoreCase(this.position);
    }

    @Override
    public String intercept(ActionInvocation invocation) throws Exception {
        // 拦截器栈底部的RedirectResultInterceptor实例负责装载actionErrors数据，否则会被DefaultWorkflowInterceptor拦截而进不了action
        if (this.isBottom()) {
            this.loadPreActionMessagesAndErrors(invocation);
        }
        String result = invocation.invoke();
        // 拦截器栈顶部的RedirectResultInterceptor实例负责向session填充actionErrors数据，因为某些情况下DefaultWorkflowInterceptor拦截而进不了底部实例
        if (this.isTop() && this.isRedirectResult(invocation)) {
            this.passToPostActionMessagesAndErrors(invocation);
        }
        return result;
    }

    @SuppressWarnings("unchecked")
    private void loadPreActionMessagesAndErrors(ActionInvocation invocation) throws Exception {
        ActionContext context = invocation.getInvocationContext();
        if (invocation.getAction() instanceof ActionSupport) {
            ActionSupport support = (ActionSupport) invocation.getAction();
            support.setActionErrors((Collection<String>) context.getSession().get(KEY_ACTION_ERRORS));
            support.setActionMessages((Collection<String>) context.getSession().get(KEY_ACTION_MESSAGES));
            support.setFieldErrors((Map<String, List<String>>) context.getSession().get(KEY_FIELD_ERRORS));
        }
        context.getSession().remove(KEY_ACTION_ERRORS);
        context.getSession().remove(KEY_ACTION_MESSAGES);
        context.getSession().remove(KEY_FIELD_ERRORS);
    }

    private void passToPostActionMessagesAndErrors(ActionInvocation invocation) throws Exception {
        ActionContext context = invocation.getInvocationContext();
        if (invocation.getAction() instanceof ActionSupport) {
            ActionSupport support = (ActionSupport) invocation.getAction();
            context.getSession().put(KEY_ACTION_MESSAGES, support.getActionMessages());
            context.getSession().put(KEY_ACTION_ERRORS, support.getActionErrors());
            context.getSession().put(KEY_FIELD_ERRORS, support.getFieldErrors());
        }
    }

    private boolean isRedirectResult(ActionInvocation invocation) throws Exception {
        Result result = invocation.getResult();
        //isAssignableFrom 判断是否是父子关系
        return result != null && ServletRedirectResult.class.isAssignableFrom(result.getClass());
    }
}
